//
//  CNM_IsolatedMaskView.swift
//  CNMTools
//
//  Created by MrHong on 2023/11/10.
//  开始创建视图时，必须设置frame。不适合layout布局

import UIKit

// MARK: - 具有相同类的不同实例工厂模式
public struct IsolatedAlertMaskFactory {
    private init() {} // 私有构造函数，防止外部创建实例

    public static let sharedInstance = IsolatedAlertMaskFactory() // 单例工厂实例

    // 创建和存储类的多个实例
    public func createInstance(identity: String) -> IsolatedAlertMaskView {
        return IsolatedAlertMaskView(identity: identity)
    }
}

// MARK: - 遮罩视图
public final class IsolatedAlertMaskView: UIView {
    public static let shared = IsolatedAlertMaskView(identity: "Normal_Mask")

    public enum MaskType {
        case alert
        case sheet
    }

    // MARK: - property
    public private(set) var isShow: Bool = false
    public var DEFAULT_BLOCKER_BACKGROUND_COLOR: UIColor = UIColor(white: 0, alpha: 0.35)
    public var DEFAULT_TOUCH_BACKGROUND: Bool = true // 是否可操作遮罩，true：点击会dismiss maskView; 反之点击遮罩没反应
    public var DEFAULT_INTERACTION_UNDER_LAYER: Bool = false // 是否可交互window的下层视图；DEFAULT_TOUCH_BACKGROUND = false & DEFAULT_INTERACTION_UNDER_LAYER = true 可用
    public var DEFAULT_NEED_AUTO_DISAPPEAR: Bool = false
    public var DEFAULT_TOUCH_DISMISS_DURATION: TimeInterval = TimeInterval(2)
  
    private var identity: String!
    private var type: MaskType = .alert
    private var dismissBlock: (() -> Void)?

    // MARK: - subview
    private var childView: UIView?
    private var bgWindow: UIWindow?

    // MARK: - life cycle
    public init(frame: CGRect = .zero, identity: String) {
        self.identity = identity
        super.init(frame: frame)
        
        if identity == "Normal_Mask" {
            DEFAULT_TOUCH_BACKGROUND = false
            DEFAULT_NEED_AUTO_DISAPPEAR = false
            DEFAULT_INTERACTION_UNDER_LAYER = false
        }
    }
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

// MARK: - Private
private extension IsolatedAlertMaskView {
    private func createWindow() -> UIWindow? {
        var window: UIWindow?

        if #available(iOS 13.0, *) {
            let windowScene = UIApplication.shared
                .connectedScenes
                .filter { $0.activationState == .foregroundActive }
                .first
            if let windowScene = windowScene as? UIWindowScene {
                // 该window是全局变量
                window = UIWindow(windowScene: windowScene)
                window?.frame = UIScreen.main.bounds
                window?.windowLevel = UIWindow.Level.normal
            }
        } else {
            window = UIWindow(frame: UIScreen.main.bounds)
            // 显示优先级, 通常会有三个值, 优先级顺序为: UIWindowLevelAlert > UIWindowLevelStatusBar > UIWindowLevelNormal
            window?.windowLevel = .normal
        }
        window?.backgroundColor = DEFAULT_BLOCKER_BACKGROUND_COLOR
        window?.isHidden = true
        window?.alpha = 0.0

        if DEFAULT_TOUCH_BACKGROUND {
            let tap = UITapGestureRecognizer(target: self, action: #selector(tapWindowAction))
            tap.delegate = self
            window?.addGestureRecognizer(tap)
        } else if DEFAULT_TOUCH_BACKGROUND == false && DEFAULT_INTERACTION_UNDER_LAYER == true {
            window?.isUserInteractionEnabled = false
        }

        return window
    }

    @objc func tapWindowAction() {
        isShow = false
        dismiss(dismissBlock)
    }

    // alert action animation
    private func showAlert() {
        isShow = true
        
        UIView.animate(withDuration: 0.25, delay: 0, options: [.curveLinear, .beginFromCurrentState], animations: {
            self.bgWindow?.isHidden = false
            self.bgWindow?.alpha = 1.0
            self.bgWindow?.makeKeyAndVisible()
        })
    }

    // sheet action animation
    private func showSheet() {
        isShow = true
        
        UIView.animate(withDuration: 0.1, animations: {
            self.bgWindow?.isHidden = false
            self.bgWindow?.alpha = 1.0
            self.bgWindow?.makeKeyAndVisible()
        }) { (_: Bool) in
            UIView.animate(withDuration: 0.25) { [self] in
                self.childView!.transform = CGAffineTransform(translationX: 0, y: -self.childView!.frame.size.height)
            }
        }
    }

    // alert dismiss animation
    private func dismissAlert(_ block: (() -> Void)? = nil) {
        isShow = false
        
        UIView.animate(withDuration: 0.25, delay: 0, options: [.curveLinear, .beginFromCurrentState], animations: {
            self.bgWindow?.alpha = 0.0
        }, completion: { _ in
            self.bgWindow?.isHidden = true
            self.childView?.removeFromSuperview()
            self.childView = nil
            self.bgWindow = nil

            if let block = block {
                block()
            }
        })
    }

    // sheet dismiss animation
    private func dismissSheet(_ block: (() -> Void)? = nil) {
        isShow = false
        
        UIView.animate(withDuration: 0.25, animations: {
            self.childView?.transform = .identity
        }) { (_: Bool) in
            UIView.animate(withDuration: 0.1) {
                self.bgWindow?.alpha = 0.0
                self.bgWindow?.isHidden = true
                self.childView?.removeFromSuperview()
                self.childView = nil
                self.bgWindow = nil
            }

            if let block = block {
                block()
            }
        }
    }
}

// MARK: - Public Action
extension IsolatedAlertMaskView {
    // sheet action
    public final func show(childView: UIView, type: IsolatedAlertMaskView.MaskType = .alert) {
        self.childView = childView
        self.type = type

        if bgWindow == nil {
            bgWindow = createWindow()
        }
        bgWindow?.addSubview(childView)
        bgWindow?.becomeKey()

        if type == .alert {
            showAlert()
        } else {
            showSheet()
        }

        if type == .alert && DEFAULT_NEED_AUTO_DISAPPEAR {
            DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + DEFAULT_TOUCH_DISMISS_DURATION) {
                self.dismissAlert()
            }
        }
    }

    public final func dismiss(_ block: (() -> Void)? = nil) {
        bgWindow?.resignKey()

        if type == .alert {
            dismissAlert(block)
        } else {
            dismissSheet(block)
        }
    }
}

// MARK: - UIGestureRecognizerDelegate
extension IsolatedAlertMaskView: UIGestureRecognizerDelegate {
    public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
        if touch.view == bgWindow {
            return true
        }
        return false
    }
}

